﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;

namespace Glucometer
{
    public enum TestUnit
    { 
        L,
        DL
    }

    public enum SetupModePosition
    {
        TEST_UNIT,
        FIRST_DIGIT_OF_YEAR,
        SECOND_DIGIT_OF_YEAR,
        //THIRD_DIGIT_OF_YEAR,
        //FOURTH_DIGIT_OF_YEAR,
        FIRST_DIGIT_OF_MONTH,
        SECOND_DIGIT_OF_MONTH,
        FIRST_DIGIT_OF_DAY,
        SECOND_DIGIT_OF_DAY,
        FIRST_DIGIT_OF_HOUR,
        SECOND_DIGIT_OF_HOUR,
        FIRST_DIGIT_OF_MINUTE,
        SECOND_DIGIT_OF_MINUTE,
        NONE
    }

    public class DeviceSettings
    {

        public event Glucometer.ModuleHandler.d_EmptyArgument DateChanged;

        private SetupModePosition _setupUnitPosition;

        public SetupModePosition SetupUnitPosition
        {
            get { return _setupUnitPosition; }
        }

        private TestUnit _testUnit;

        public TestUnit TestUnit
        {
            get { return _testUnit; }
            set { TestUnit = value; }
        }

        private int _century;

        public int Century
        {
            get { return _century; }
            set { _century = value; }
        }

        private int _first_digit_of_year;

        public int First_digit_of_year
        {
            get { return _first_digit_of_year; }
            set { _first_digit_of_year = value; }
        }

        private int _second_digit_of_year;

        public int Second_digit_of_year
        {
            get { return _second_digit_of_year; }
            set { _second_digit_of_year = value; }
        }

        //private int _third_digit_of_year;

        //public int Third_digit_of_year
        //{
        //    get { return _third_digit_of_year; }
        //    set { _third_digit_of_year = value; }
        //}

        //private int _fourth_digit_of_year;

        //public int Fourth_digit_of_year
        //{
        //    get { return _fourth_digit_of_year; }
        //    set { _fourth_digit_of_year = value; }
        //}

        private int _first_digit_of_month;

        public int First_digit_of_month
        {
            get { return _first_digit_of_month; }
            set { _first_digit_of_month = value; }
        }

        private int _second_digit_of_month;

        public int Second_digit_of_month
        {
            get { return _second_digit_of_month; }
            set { _second_digit_of_month = value; }
        }

        private int _first_digit_of_day;

        public int First_digit_of_day
        {
            get { return _first_digit_of_day; }
            set { _first_digit_of_day = value; }
        }

        private int _second_digit_of_day;

        public int Second_digit_of_day
        {
            get { return _second_digit_of_day; }
            set { _second_digit_of_day = value; }
        }

        private int _first_digit_of_hour;

        public int First_digit_of_hour
        {
            get { return _first_digit_of_hour; }
            set { _first_digit_of_hour = value; }
        }

        private int _second_digit_of_hour;

        private int _first_digit_of_minute;

        public int First_digit_of_minute
        {
            get { return _first_digit_of_minute; }
            set { _first_digit_of_minute = value; }
        }

        private int _second_digit_of_minute;

        public int Second_digit_of_minute
        {
            get { return _second_digit_of_minute; }
            set { _second_digit_of_minute = value; }
        }

        private int _tickCount = 0;

        public int TickCount
        {
            get { return _tickCount; }
        }

        public DeviceSettings(int century)
        {
            //INITIALIZE THE SETTING WITH FACTORY DEFALUT
            this._testUnit = TestUnit.L;

            this._first_digit_of_year = 0;

            this._second_digit_of_year =
                //this._third_digit_of_year =
                //this._fourth_digit_of_year = 
                this._first_digit_of_month =
                this._first_digit_of_day = 
                this._first_digit_of_hour =
                this._second_digit_of_hour =
                this.First_digit_of_minute =
                this.Second_digit_of_minute = 0;

            this._second_digit_of_month = this._second_digit_of_day = 1;

            this._testUnit = TestUnit.L;

            this._century = century;

            this._setupUnitPosition = SetupModePosition.TEST_UNIT;
        }

        public void LoadSetting(TestUnit tu, DateTime dt, int tickcount)
        {
            this._testUnit = tu;

            //this.First_digit_of_day = dt.Year / 1000;
            //this.Second_digit_of_year = (dt.Year / 100) - (this.First_digit_of_day * 10);
            //this.Third_digit_of_year = (dt.Year / 10) - (this.First_digit_of_day * 100) - (this.Second_digit_of_year * 10);
            //this.Fourth_digit_of_year = (dt.Year) - (this.First_digit_of_day * 1000) - 
            //                            (this.Second_digit_of_year * 100) - 
            //                            (this.Third_digit_of_year * 10);

            this._first_digit_of_year = (dt.Year - this._century) / 10;
            this.Second_digit_of_year = (dt.Year - this._century) - (10 * this._first_digit_of_year);

            this._first_digit_of_month = dt.Month / 10;
            this.Second_digit_of_month = dt.Month - this._first_digit_of_month * 10;

            this._first_digit_of_day = dt.Day / 10;
            this.Second_digit_of_day = dt.Day - this._first_digit_of_day * 10;

            this.First_digit_of_hour = dt.Hour / 10;
            this._second_digit_of_hour = dt.Hour - this._first_digit_of_hour * 10;

            this.First_digit_of_minute = dt.Minute / 10;
            this.Second_digit_of_minute = dt.Minute - this.First_digit_of_minute * 10;

            _tickCount = tickcount;

            _setupUnitPosition = SetupModePosition.TEST_UNIT;
        }

        public void setSetting(TestUnit tu, DateTime dt)
        {
            //WHEN THE USER SETS THE SETTING THE TICK COUNT SHOULD BE SET AS 0
            LoadSetting(tu, dt, 0);
        }

        public bool IncrementCurrentPositionSettingValue()
        {
            switch (this._setupUnitPosition)
            {
                case SetupModePosition.TEST_UNIT:
                    this._testUnit = (this._testUnit == Glucometer.TestUnit.L) ? Glucometer.TestUnit.DL : Glucometer.TestUnit.L;
                    break;
                case SetupModePosition.FIRST_DIGIT_OF_YEAR:
                    this._first_digit_of_year = (this._first_digit_of_year + 1) % 10;                    
                    break;
                case SetupModePosition.SECOND_DIGIT_OF_YEAR:
                    this._second_digit_of_year = (this._second_digit_of_year + 1) % 10;                    
                    break;
                //case SetupModePosition.THIRD_DIGIT_OF_YEAR:
                //    this._third_digit_of_year = (this._third_digit_of_year + 1) % 10;
                //    break;
                //case SetupModePosition.FOURTH_DIGIT_OF_YEAR:
                //    this._fourth_digit_of_year = (this._fourth_digit_of_year + 1) % 10;
                //    break;
                case SetupModePosition.FIRST_DIGIT_OF_MONTH:
                    this._first_digit_of_month = (this._first_digit_of_month == 0) ? 1 : 0;
                    break;
                case SetupModePosition.SECOND_DIGIT_OF_MONTH:
                    this._second_digit_of_month = (this._second_digit_of_month + 1) % 10;
                    break;
                case SetupModePosition.FIRST_DIGIT_OF_DAY:
                    this._first_digit_of_day = (this._first_digit_of_day + 1) % 4;
                    break;
                case SetupModePosition.SECOND_DIGIT_OF_DAY:
                    if (this._first_digit_of_day <= 2)
                        this._second_digit_of_day = (this._second_digit_of_day + 1) % 10;
                    else if (this._first_digit_of_day == 3)
                    {
                        this._second_digit_of_day = (this._second_digit_of_day + 1) % 2;
                    }
                    break;
                case SetupModePosition.FIRST_DIGIT_OF_HOUR:
                    this._first_digit_of_hour = (this._first_digit_of_hour + 1) % 3;
                    break;
                case SetupModePosition.SECOND_DIGIT_OF_HOUR:
                    if(this._first_digit_of_hour == 2)
                        this._second_digit_of_hour = (this._second_digit_of_hour + 1) % 4;
                    else
                        this._second_digit_of_hour = (this._second_digit_of_hour + 1) % 10;
                    break;
                case SetupModePosition.FIRST_DIGIT_OF_MINUTE:
                    this._first_digit_of_minute = (this._first_digit_of_minute + 1) % 6;
                    break;
                case SetupModePosition.SECOND_DIGIT_OF_MINUTE:
                    this._second_digit_of_minute = (this._second_digit_of_minute + 1) % 10;
                    break;
            }
            return true; 
        }

        public bool MoveToNextPosition()
        {
            switch (this._setupUnitPosition)
            { 
                case SetupModePosition.TEST_UNIT:
                    this._setupUnitPosition = SetupModePosition.FIRST_DIGIT_OF_YEAR;
                    break;
                case SetupModePosition.FIRST_DIGIT_OF_YEAR:
                    this._setupUnitPosition = SetupModePosition.SECOND_DIGIT_OF_YEAR;
                    break;
                case SetupModePosition.SECOND_DIGIT_OF_YEAR:
                    //this._setupUnitPosition = SetupModePosition.THIRD_DIGIT_OF_YEAR;
                    this._setupUnitPosition = SetupModePosition.FIRST_DIGIT_OF_MONTH;
                    break;
                //case SetupModePosition.THIRD_DIGIT_OF_YEAR:
                //    this._setupUnitPosition = SetupModePosition.FOURTH_DIGIT_OF_YEAR;
                //    break;
                //case SetupModePosition.FOURTH_DIGIT_OF_YEAR:
                //    this._setupUnitPosition = SetupModePosition.FIRST_DIGIT_OF_MONTH;
                //    break;
                case SetupModePosition.FIRST_DIGIT_OF_MONTH:
                    this._setupUnitPosition = SetupModePosition.SECOND_DIGIT_OF_MONTH;
                    break;
                case SetupModePosition.SECOND_DIGIT_OF_MONTH:
                    //IF THE FIRST DIGIT IS SET TO 0 THEN NO PROBLEM
                    //IF THE FIRST DIGIT IS SET TO 1 AND THE SECOND DIGIT EXCEEDS 2 
                    //THEN ITS ERROR SO JUST RETURN FALSE 
                    
                    if (this._first_digit_of_month == 1 && this._second_digit_of_month > 2)                    
                        return false;
                    //ALSO CHECK MONTH CANT BE SET TO 00
                    if (this._first_digit_of_month == 0 && this._second_digit_of_month == 0)
                        return false;
                    this._setupUnitPosition = SetupModePosition.FIRST_DIGIT_OF_DAY;
                    break;
                case SetupModePosition.FIRST_DIGIT_OF_DAY:
                    this._setupUnitPosition = SetupModePosition.SECOND_DIGIT_OF_DAY;
                    break;
                case SetupModePosition.SECOND_DIGIT_OF_DAY:
                    //RETURN FALSE IF THE DATE SET IS NOT VALID
                    if (!IsValidDateSet())
                        return false;
                    this._setupUnitPosition = SetupModePosition.FIRST_DIGIT_OF_HOUR;
                    break;
                case SetupModePosition.FIRST_DIGIT_OF_HOUR:
                    this._setupUnitPosition = SetupModePosition.SECOND_DIGIT_OF_HOUR;
                    break;
                case SetupModePosition.SECOND_DIGIT_OF_HOUR:
                    //IF THE FIRST DIGIT OF HOUR IS 2 THEN THE SECOND DIGIT SHOULD NOT EXCEED 3
                    if (this._first_digit_of_hour == 2 && this._second_digit_of_hour > 3)
                        return false;
                    this._setupUnitPosition = SetupModePosition.FIRST_DIGIT_OF_MINUTE;
                    break;
                case SetupModePosition.FIRST_DIGIT_OF_MINUTE:
                    this._setupUnitPosition = SetupModePosition.SECOND_DIGIT_OF_MINUTE;
                    break;
                case SetupModePosition.SECOND_DIGIT_OF_MINUTE:
                    this._setupUnitPosition = SetupModePosition.NONE;
                    break;
                default:
                    return false;
            }

            return true;
        }

        public bool IsValidDateSet()
        {
            try
            {
                new DateTime(GetYear(), GetMonth(), getDay(), 00, 00, 00);
            }
            catch { return false; }
            return true;
        }

        private int GetYear()
        {
            return this._century + 10 * this._first_digit_of_year + this.Second_digit_of_year;
        }

        private int GetMonth()
        {
            return 10 * this._first_digit_of_month + this._second_digit_of_month;
        }

        private int getDay()
        {
            return 10 * this._first_digit_of_day + this._second_digit_of_day;
        }

        private int GetHour()
        {
            return 10 * this._first_digit_of_hour + this._second_digit_of_hour;
        }

        private int GetMinute()
        {
            return 10 * this._first_digit_of_minute + this._second_digit_of_minute;
        }

        public DateTime getDateTime()
        {
            int year = this._century + 10 * this._first_digit_of_year + this._second_digit_of_year;

            int month = 10 * _first_digit_of_month + _second_digit_of_month;

            int day = 10 * _first_digit_of_day + _second_digit_of_day;

            int hour = 10 * _first_digit_of_hour + _second_digit_of_hour;

            int minute = 10 * _first_digit_of_minute + _second_digit_of_minute;

            return new DateTime(year, month, day, hour, minute, 00);
        }

        public string CurrentSetupPositionValue
        {
            get 
            {
                string c = string.Empty;
                switch (this._setupUnitPosition)
                {
                    case SetupModePosition.TEST_UNIT:
                        c = _testUnit.ToString();
                        break;
                    case SetupModePosition.FIRST_DIGIT_OF_YEAR:
                        c = First_digit_of_year.ToString();
                        break;
                    case SetupModePosition.SECOND_DIGIT_OF_YEAR:
                        c = Second_digit_of_year.ToString();
                        break;
                    case SetupModePosition.FIRST_DIGIT_OF_MONTH:
                        c = First_digit_of_month.ToString();
                        break;
                    case SetupModePosition.SECOND_DIGIT_OF_MONTH:
                        c = Second_digit_of_month.ToString();
                        break;
                    case SetupModePosition.FIRST_DIGIT_OF_DAY:
                        c = First_digit_of_day.ToString();
                        break;
                    case SetupModePosition.SECOND_DIGIT_OF_DAY:
                        c = Second_digit_of_day.ToString();
                        break;
                    case SetupModePosition.FIRST_DIGIT_OF_HOUR:
                        c = First_digit_of_hour.ToString();
                        break;
                    case SetupModePosition.SECOND_DIGIT_OF_HOUR:
                        c = _second_digit_of_hour.ToString();
                        break;
                    case SetupModePosition.FIRST_DIGIT_OF_MINUTE:
                        c = First_digit_of_minute.ToString();
                        break;
                    case SetupModePosition.SECOND_DIGIT_OF_MINUTE:
                        c = Second_digit_of_minute.ToString();
                        break;
                }

                return c;
            }
        }

        public void updateTick()
        {
            int oldTickCount = TickCount;

            this._tickCount = (this.TickCount + 1);

            //THIS MEANS THE MINUTE VALUE CHANGED, SO WE NEED TO UPDATE DATETIME
            if ((this.TickCount + 1) % 60 == 0)
            {
                addOneMinute();

                //NOTIFY THAT THE DATETIME CHANGED
                if (DateChanged != null)
                {
                    DateChanged();
                }
            }
        }

        private void addOneMinute()
        {
            //ADD ONE MINUTE TO CURRENT DATETIME AND LOAD THIS CHANGED DATETIME
            //THE MODIFIED DATE MUST NOT CHANGE
            LoadSetting(this._testUnit, this.getDateTime().AddMinutes(1), this.TickCount);
        }
    }
}